{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## What is AutoML?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.collections.PathCollection at 0x1228a9860>"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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Ksrn6//q4sVF5fOt0ZUw40ol1vMFRd0FR90FQ70FR93V59qS7erq0tjY2My/p6enbQNWEgELAMB/cQ3ZD3/4w/rtb38rSdq1a5fWrGGfUAAAvMhZlmU5PaE6u3hgYECWZemBBx7QWWedFVf5AADILNeQBQAAwbAZBQAAhhCyAAAYQsgCAGAIIRvS9PS07r33Xm3atEn9/f06cODAnMd/+MMf6oorrlB/f79G+VxeAAACzklEQVT6+/u1f//+hEqaXrt371Z/f/+8n//617/WNddco02bNunxxx9PoGTpZ1d3HHf2pqamdOedd+rGG2/Utddeq1/96ldzHue4q8+t3jjmbFgI5emnn7buuusuy7Is689//rP1+c9/fs7jd9xxh7Vnz54kipYJW7Zssa688kpr48aNc34+OTlpXXbZZdbw8LB14sQJ6+qrr7YGBwcTKmU62dWdZXHcOXniiSes+++/37Isyzp69KjV19c38xjHnT2nerMsjjk7tGRDctt2cu/evdqyZYtuuOEGPfroo0kUMdVWrFihhx56aN7P9+3bpxUrVmjRokVqb2/XRRddpOeeey6BEqaXXd1JHHdO1q9fr9tuu02SZFmWWlvf3UCH486eU71JHHN2CNmQ7LadrLriiit033336bHHHtPOnTv1zDPPJFHM1Lr88svr7iA2OjqqBQve3aats7NTo6OjcRYt9ezqTuK4c9LZ2amuri6Njo7qi1/8om6//faZxzju7DnVm8QxZ4eQDclp20nLsnTzzTerp6dH7e3t6uvr0wsvvJBUUTOltl7HxsbmnPxgj+PO3cGDB3XTTTfpU5/6lK666qqZn3PcObOrN445e4RsSE7bTo6OjurKK6/U2NiYLMvSH/7wB51//vlJFTVTzjrrLB04cEDDw8OanJzUn/70J33oQx9KuliZwHHnbGhoSLfccovuvPNOXXvttXMe47iz51RvHHP2XO/CA2fr1q3Tjh07dP31189sO/nzn/9c5XJZmzZt0pe+9CXddNNNam9v1yWXXKK+vr6ki5xqs+vuK1/5ij772c/Ksixdc801Ou2005IuXqpx3HnzyCOPaGRkRA8//LAefvhhSdLGjRs1Pj7OcefArd445upjW0UAAAyhuxgAAEMIWQAADCFkAQAwhJAFAMAQQhYAAEMIWQAADCFkAQAwhJAFAMCQ/w/utjFFdyBjPgAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x111f4def0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Sklearn has convenient modules to create sample data.\n",
    "# make_blobs will help us to create a sample data set suitable for clustering\n",
    "from sklearn.datasets.samples_generator import make_blobs\n",
    "\n",
    "X, y = make_blobs(n_samples=100, centers=2, cluster_std=0.30, random_state=0)\n",
    "\n",
    "# Let's visualize what we have first\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import seaborn as sns\n",
    "\n",
    "plt.scatter(X[:, 0], X[:, 1], s=50)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.collections.PathCollection at 0x123413710>"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x12319ac88>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# We will import KMeans model from clustering model family of Sklearn\n",
    "from sklearn.cluster import KMeans\n",
    "\n",
    "k_means = KMeans(n_clusters=2)\n",
    "k_means.fit(X)\n",
    "predictions = k_means.predict(X)\n",
    "\n",
    "# Let's plot the predictions\n",
    "plt.scatter(X[:, 0], X[:, 1], c=predictions, cmap='brg')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'algorithm': 'auto',\n",
       " 'copy_x': True,\n",
       " 'init': 'k-means++',\n",
       " 'max_iter': 300,\n",
       " 'n_clusters': 2,\n",
       " 'n_init': 10,\n",
       " 'n_jobs': 1,\n",
       " 'precompute_distances': 'auto',\n",
       " 'random_state': None,\n",
       " 'tol': 0.0001,\n",
       " 'verbose': 0}"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "k_means.get_params()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Featuretools"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style>\n",
       "    .dataframe thead tr:only-child th {\n",
       "        text-align: right;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: left;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>creation_date</th>\n",
       "      <th>database_id</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>2018-02-01</td>\n",
       "      <td>2234</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>2017-03-02</td>\n",
       "      <td>1765</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>2017-05-03</td>\n",
       "      <td>8796</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>2013-05-12</td>\n",
       "      <td>2237</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>2012-05-09</td>\n",
       "      <td>3398</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "  creation_date  database_id\n",
       "0    2018-02-01         2234\n",
       "1    2017-03-02         1765\n",
       "2    2017-05-03         8796\n",
       "3    2013-05-12         2237\n",
       "4    2012-05-09         3398"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "\n",
    "# First dataset contains the basic information for databases.\n",
    "databases_df = pd.DataFrame({\"database_id\": [2234, 1765, 8796, 2237, 3398],\n",
    "\"creation_date\": [\"2018-02-01\", \"2017-03-02\", \"2017-05-03\", \"2013-05-12\", \"2012-05-09\"]})\n",
    "\n",
    "databases_df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style>\n",
       "    .dataframe thead tr:only-child th {\n",
       "        text-align: right;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: left;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>database_id</th>\n",
       "      <th>transaction_date</th>\n",
       "      <th>transaction_id</th>\n",
       "      <th>transaction_size</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>2234</td>\n",
       "      <td>2018-02-02</td>\n",
       "      <td>26482746</td>\n",
       "      <td>10</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1765</td>\n",
       "      <td>2018-03-02</td>\n",
       "      <td>19384752</td>\n",
       "      <td>20</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>2234</td>\n",
       "      <td>2018-03-02</td>\n",
       "      <td>48571125</td>\n",
       "      <td>30</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>2237</td>\n",
       "      <td>2018-04-02</td>\n",
       "      <td>78546789</td>\n",
       "      <td>50</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>1765</td>\n",
       "      <td>2018-04-02</td>\n",
       "      <td>19998765</td>\n",
       "      <td>100</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   database_id transaction_date  transaction_id  transaction_size\n",
       "0         2234       2018-02-02        26482746                10\n",
       "1         1765       2018-03-02        19384752                20\n",
       "2         2234       2018-03-02        48571125                30\n",
       "3         2237       2018-04-02        78546789                50\n",
       "4         1765       2018-04-02        19998765               100"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Second dataset contains the information of transaction for each database id\n",
    "db_transactions_df = pd.DataFrame({\"transaction_id\": [26482746, 19384752, 48571125, 78546789, 19998765, 26482646, 12484752, 42471125, 75346789, 16498765, 65487547, 23453847, 56756771, 45645667, 23423498, 12335268, 76435357, 34534711, 45656746, 12312987],\n",
    "                \"database_id\": [2234, 1765, 2234, 2237, 1765, 8796, 2237, 8796, 3398, 2237, 3398, 2237, 2234, 8796, 1765, 2234, 2237, 1765, 8796, 2237],\n",
    "                \"transaction_size\": [10, 20, 30, 50, 100, 40, 60, 60, 10, 20, 60, 50, 40, 40, 30, 90, 130, 40, 50, 30],\n",
    "                \"transaction_date\": [\"2018-02-02\", \"2018-03-02\", \"2018-03-02\", \"2018-04-02\", \"2018-04-02\", \"2018-05-02\", \"2018-06-02\", \"2018-06-02\", \"2018-07-02\", \"2018-07-02\", \"2018-01-03\", \"2018-02-03\", \"2018-03-03\", \"2018-04-03\", \"2018-04-03\", \"2018-07-03\", \"2018-07-03\", \"2018-07-03\", \"2018-08-03\", \"2018-08-03\"]})\n",
    "\n",
    "db_transactions_df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'databases': (  creation_date  database_id\n",
      "0    2018-02-01         2234\n",
      "1    2017-03-02         1765\n",
      "2    2017-05-03         8796\n",
      "3    2013-05-12         2237\n",
      "4    2012-05-09         3398, 'database_id'), 'transactions': (    database_id transaction_date  transaction_id  transaction_size\n",
      "0          2234       2018-02-02        26482746                10\n",
      "1          1765       2018-03-02        19384752                20\n",
      "2          2234       2018-03-02        48571125                30\n",
      "3          2237       2018-04-02        78546789                50\n",
      "4          1765       2018-04-02        19998765               100\n",
      "5          8796       2018-05-02        26482646                40\n",
      "6          2237       2018-06-02        12484752                60\n",
      "7          8796       2018-06-02        42471125                60\n",
      "8          3398       2018-07-02        75346789                10\n",
      "9          2237       2018-07-02        16498765                20\n",
      "10         3398       2018-01-03        65487547                60\n",
      "11         2237       2018-02-03        23453847                50\n",
      "12         2234       2018-03-03        56756771                40\n",
      "13         8796       2018-04-03        45645667                40\n",
      "14         1765       2018-04-03        23423498                30\n",
      "15         2234       2018-07-03        12335268                90\n",
      "16         2237       2018-07-03        76435357               130\n",
      "17         1765       2018-07-03        34534711                40\n",
      "18         8796       2018-08-03        45656746                50\n",
      "19         2237       2018-08-03        12312987                30, 'transaction_id')}\n"
     ]
    }
   ],
   "source": [
    "# Entities for each of datasets should be defined\n",
    "entities = {\n",
    "\"databases\" : (databases_df, \"database_id\"),\n",
    "\"transactions\" : (db_transactions_df, \"transaction_id\")\n",
    "}\n",
    "\n",
    "# Relationships between tables should also be defined as below\n",
    "relationships = [(\"databases\", \"database_id\", \"transactions\", \"database_id\")]\n",
    "\n",
    "print(entities)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[<Feature: SUM(transactions.transaction_size)>,\n",
       " <Feature: STD(transactions.transaction_size)>,\n",
       " <Feature: MAX(transactions.transaction_size)>,\n",
       " <Feature: SKEW(transactions.transaction_size)>,\n",
       " <Feature: MIN(transactions.transaction_size)>,\n",
       " <Feature: MEAN(transactions.transaction_size)>,\n",
       " <Feature: COUNT(transactions)>,\n",
       " <Feature: DAY(creation_date)>,\n",
       " <Feature: YEAR(creation_date)>,\n",
       " <Feature: MONTH(creation_date)>,\n",
       " <Feature: WEEKDAY(creation_date)>,\n",
       " <Feature: NUM_UNIQUE(transactions.DAY(transaction_date))>,\n",
       " <Feature: NUM_UNIQUE(transactions.YEAR(transaction_date))>,\n",
       " <Feature: NUM_UNIQUE(transactions.MONTH(transaction_date))>,\n",
       " <Feature: NUM_UNIQUE(transactions.WEEKDAY(transaction_date))>,\n",
       " <Feature: MODE(transactions.DAY(transaction_date))>,\n",
       " <Feature: MODE(transactions.YEAR(transaction_date))>,\n",
       " <Feature: MODE(transactions.MONTH(transaction_date))>,\n",
       " <Feature: MODE(transactions.WEEKDAY(transaction_date))>]"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# There are 2 entities called ‘databases’ and ‘transactions’\n",
    "# All the pieces that are necessary to engineer features are in place, you can create your feature matrix as below\n",
    "\n",
    "import featuretools as ft\n",
    "\n",
    "feature_matrix_db_transactions, feature_defs = ft.dfs(entities=entities, relationships=relationships, target_entity=\"databases\")\n",
    "\n",
    "feature_defs"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Auto-sklearn"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x1241dbda0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Necessary imports\n",
    "import autosklearn.classification\n",
    "import sklearn.model_selection\n",
    "import sklearn.datasets\n",
    "import sklearn.metrics\n",
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "# Digits dataset is one of the most popular datasets in machine learning community.\n",
    "# Every example in this datasets represents a 8x8 image of a digit.\n",
    "X, y = sklearn.datasets.load_digits(return_X_y=True)\n",
    "\n",
    "# Let's see the first image. Image is reshaped to 8x8, otherwise it's a vector of size 64.\n",
    "X[0].reshape(8,8)\n",
    "\n",
    "# Let's also plot couple of them\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "\n",
    "number_of_images = 10\n",
    "images_and_labels = list(zip(X, y))\n",
    "\n",
    "for i, (image, label) in enumerate(images_and_labels[:number_of_images]):\n",
    "    plt.subplot(2, number_of_images, i + 1)\n",
    "    plt.axis('off')\n",
    "    plt.imshow(image.reshape(8,8), cmap=plt.cm.gray_r, interpolation='nearest')\n",
    "    plt.title('%i' % label)\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Accuracy score 0.9933333333333333\n"
     ]
    }
   ],
   "source": [
    "# We split our dataset to train and test data\n",
    "X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=1)\n",
    "\n",
    "# Similarly to creating an estimator in Scikit-learn, we create AutoSklearnClassifier\n",
    "automl = autosklearn.classification.AutoSklearnClassifier()\n",
    "\n",
    "# All you need to do is to invoke fit method to start experiment with different feature engineering methods and machine learning models\n",
    "automl.fit(X_train, y_train)\n",
    "\n",
    "# Generating predictions is same as Scikit-learn, you need to invoke predict method.\n",
    "y_hat = automl.predict(X_test)\n",
    "\n",
    "print(\"Accuracy score\", sklearn.metrics.accuracy_score(y_test, y_hat))\n",
    "# Accuracy score 0.98"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## MLBox"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/umitcakmak/anaconda/lib/python3.6/site-packages/h5py/__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.\n",
      "  from ._conv import register_converters as _register_converters\n",
      "Using Theano backend.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "GoSales_Tx_NaiveBayes (1).csv\n"
     ]
    }
   ],
   "source": [
    "# Necessary Imports\n",
    "from mlbox.preprocessing import *\n",
    "from mlbox.optimisation import *\n",
    "from mlbox.prediction import *\n",
    "import wget\n",
    "\n",
    "file_link = 'https://apsportal.ibm.com/exchange-api/v1/entries/8044492073eb964f46597b4be06ff5ea/data?accessKey=9561295fa407698694b1e254d0099600'\n",
    "file_name = wget.download(file_link)\n",
    "\n",
    "print(file_name)\n",
    "# GoSales_Tx_NaiveBayes.csv"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style>\n",
       "    .dataframe thead tr:only-child th {\n",
       "        text-align: right;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: left;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>PRODUCT_LINE</th>\n",
       "      <th>GENDER</th>\n",
       "      <th>AGE</th>\n",
       "      <th>MARITAL_STATUS</th>\n",
       "      <th>PROFESSION</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>Personal Accessories</td>\n",
       "      <td>M</td>\n",
       "      <td>27</td>\n",
       "      <td>Single</td>\n",
       "      <td>Professional</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>Personal Accessories</td>\n",
       "      <td>F</td>\n",
       "      <td>39</td>\n",
       "      <td>Married</td>\n",
       "      <td>Other</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>Mountaineering Equipment</td>\n",
       "      <td>F</td>\n",
       "      <td>39</td>\n",
       "      <td>Married</td>\n",
       "      <td>Other</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>Personal Accessories</td>\n",
       "      <td>F</td>\n",
       "      <td>56</td>\n",
       "      <td>Unspecified</td>\n",
       "      <td>Hospitality</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>Golf Equipment</td>\n",
       "      <td>M</td>\n",
       "      <td>45</td>\n",
       "      <td>Married</td>\n",
       "      <td>Retired</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "               PRODUCT_LINE GENDER  AGE MARITAL_STATUS    PROFESSION\n",
       "0      Personal Accessories      M   27         Single  Professional\n",
       "1      Personal Accessories      F   39        Married         Other\n",
       "2  Mountaineering Equipment      F   39        Married         Other\n",
       "3      Personal Accessories      F   56    Unspecified   Hospitality\n",
       "4            Golf Equipment      M   45        Married       Retired"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import pandas as pd\n",
    "df = pd.read_csv('GoSales_Tx_NaiveBayes.csv')\n",
    "df.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "test_df = df.drop(['PRODUCT_LINE'], axis = 1)\n",
    "\n",
    "# First 300 records saved as test datased\n",
    "test_df[:300].to_csv('test_data.csv')\n",
    "\n",
    "paths = [\"GoSales_Tx_NaiveBayes.csv\", \"test_data.csv\"]\n",
    "target_name = \"PRODUCT_LINE\"\n",
    "\n",
    "rd = Reader(sep = ',')\n",
    "df = rd.train_test_split(paths, target_name)\n",
    "\n",
    "dft = Drift_thresholder()\n",
    "df = dft.fit_transform(df)\n",
    "\n",
    "opt = Optimiser(scoring = 'accuracy', n_folds = 3)\n",
    "opt.evaluate(None, df)\n",
    "\n",
    "space = {\n",
    "        'ne__numerical_strategy':{\"search\":\"choice\", \"space\":[0]},\n",
    "        'ce__strategy':{\"search\":\"choice\",\n",
    "               \"space\":[\"label_encoding\",\"random_projection\", \"entity_embedding\"]},\n",
    "        'fs__threshold':{\"search\":\"uniform\", \"space\":[0.01,0.3]},\n",
    "        'est__max_depth':{\"search\":\"choice\", \"space\":[3,4,5,6,7]}\n",
    "        }\n",
    "\n",
    "best = opt.optimise(space, df,15)\n",
    "\n",
    "predictor = Predictor()\n",
    "predictor.fit_predict(best, df)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## TPOT"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Version 0.8.3 of tpot is outdated. Version 0.9.3 was released 3 days ago.\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Optimization Progress:  17%|█▋        | 57/330 [02:32<10:19,  2.27s/pipeline] "
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Generation 1 - Current best internal CV score: 0.9873759768128435\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Optimization Progress:  25%|██▌       | 84/330 [04:06<12:03,  2.94s/pipeline]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Generation 2 - Current best internal CV score: 0.9873759768128435\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Optimization Progress:  33%|███▎      | 110/330 [05:43<10:56,  2.98s/pipeline]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Generation 3 - Current best internal CV score: 0.9873759768128435\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Optimization Progress:  42%|████▏     | 138/330 [06:48<06:43,  2.10s/pipeline]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Generation 4 - Current best internal CV score: 0.9881194712366353\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Optimization Progress:  51%|█████     | 168/330 [08:44<09:58,  3.69s/pipeline]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Generation 5 - Current best internal CV score: 0.9881194712366353\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Optimization Progress:  60%|█████▉    | 197/330 [11:59<12:55,  5.83s/pipeline]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Generation 6 - Current best internal CV score: 0.9881194712366353\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Optimization Progress:  69%|██████▉   | 227/330 [13:22<05:01,  2.93s/pipeline]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Generation 7 - Current best internal CV score: 0.9881194712366353\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Optimization Progress:  77%|███████▋  | 254/330 [14:14<02:08,  1.69s/pipeline]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Generation 8 - Current best internal CV score: 0.9881194712366353\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Optimization Progress:  85%|████████▌ | 281/330 [14:48<01:16,  1.56s/pipeline]"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Generation 9 - Current best internal CV score: 0.9888685349070473\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "                                                                              "
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Generation 10 - Current best internal CV score: 0.9888685349070473\n",
      "\n",
      "Best pipeline: KNeighborsClassifier(DecisionTreeClassifier(input_matrix, DecisionTreeClassifier__criterion=entropy, DecisionTreeClassifier__max_depth=6, DecisionTreeClassifier__min_samples_leaf=2, DecisionTreeClassifier__min_samples_split=2), KNeighborsClassifier__n_neighbors=2, KNeighborsClassifier__p=DEFAULT, KNeighborsClassifier__weights=distance)\n",
      "0.9844444444444445\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "\r"
     ]
    }
   ],
   "source": [
    "from tpot import TPOTClassifier\n",
    "from sklearn.datasets import load_digits\n",
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "# Digits dataset that you have used in Auto-sklearn example\n",
    "digits = load_digits()\n",
    "X_train, X_test, y_train, y_test = train_test_split(digits.data, digits.target,\n",
    "                                                    train_size=0.75, test_size=0.25)\n",
    "\n",
    "# You will create your TPOT classifier with commonly used arguments\n",
    "tpot = TPOTClassifier(generations=10, population_size=30, verbosity=2)\n",
    "\n",
    "# When you invoke fit method, TPOT will create generations of populations, seeking best set of parameters. Arguments you have used to create TPOTClassifier such as generaions and population_size will affect the search space and resulting pipeline.\n",
    "tpot.fit(X_train, y_train)\n",
    "\n",
    "print(tpot.score(X_test, y_test))\n",
    "# 0.9834"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "tpot.export('my_pipeline.py')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "import numpy as np\r\n",
      "\r\n",
      "from sklearn.model_selection import train_test_split\r\n",
      "from sklearn.neighbors import KNeighborsClassifier\r\n",
      "from sklearn.pipeline import make_pipeline, make_union\r\n",
      "from sklearn.tree import DecisionTreeClassifier\r\n",
      "from tpot.builtins import StackingEstimator\r\n",
      "\r\n",
      "# NOTE: Make sure that the class is labeled 'class' in the data file\r\n",
      "tpot_data = np.recfromcsv('PATH/TO/DATA/FILE', delimiter='COLUMN_SEPARATOR', dtype=np.float64)\r\n",
      "features = np.delete(tpot_data.view(np.float64).reshape(tpot_data.size, -1), tpot_data.dtype.names.index('class'), axis=1)\r\n",
      "training_features, testing_features, training_target, testing_target = \\\r\n",
      "    train_test_split(features, tpot_data['class'], random_state=42)\r\n",
      "\r\n",
      "exported_pipeline = make_pipeline(\r\n",
      "    StackingEstimator(estimator=DecisionTreeClassifier(criterion=\"entropy\", max_depth=6, min_samples_leaf=2, min_samples_split=2)),\r\n",
      "    KNeighborsClassifier(n_neighbors=2, weights=\"distance\")\r\n",
      ")\r\n",
      "\r\n",
      "exported_pipeline.fit(training_features, training_target)\r\n",
      "results = exported_pipeline.predict(testing_features)\r\n"
     ]
    }
   ],
   "source": [
    "!cat my_pipeline.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.neighbors import KNeighborsClassifier\n",
    "\n",
    "exported_pipeline = make_pipeline(\n",
    "    StackingEstimator(estimator=DecisionTreeClassifier(criterion=\"entropy\", max_depth=6, min_samples_leaf=2, min_samples_split=2)),\n",
    "    KNeighborsClassifier(n_neighbors=2, weights=\"distance\")\n",
    ")\n",
    "\n",
    "exported_pipeline.fit(X_train, y_train)\n",
    "results = exported_pipeline.predict(X_test)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
